package com.faner.fast.util;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import com.faner.fast.exception.FailedException;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.Locale;

/**
 * description: DateUtil
 * date: 2020/11/23 13:26
 * author: faner
 */
public class DateUtils {

    public static final String FULL_TIME_PATTERN = "yyyyMMddHHmmss";
    public static final String FULL_TIME_SPLIT_PATTERN = "yyyy-MM-dd HH:mm:ss";
    public static final String CST_TIME_PATTERN = "EEE MMM dd HH:mm:ss zzz yyyy";
    public static final DateTimeFormatter DFY_MD_HMS = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    public static final DateTimeFormatter DFY_MD = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    /**
     * LocalDateTime 转时间戳
     * 获取指定日期的毫秒
     * @param time   time
     * @return {@link Long}
     */
    public static Long getMilliByTime(LocalDateTime time) {
        return time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }
    /**
     * LocalDateTime 转时间戳
     * 获取指定日期的秒
     * @param time   time
     * @return {@link Long}
     */
    public static Long getSecondsByTime(LocalDateTime time) {
        return time.atZone(ZoneId.systemDefault()).toInstant().getEpochSecond();
    }
    /**
     * 秒时间戳转LocalDateTime
     * @param secondTimeStamp /
     * @return LocalDateTime
     */
    public static LocalDateTime covertSecondTimeStampToLocalDateTime(Long secondTimeStamp) {
        return LocalDateTime.ofEpochSecond(secondTimeStamp, 0, OffsetDateTime.now().getOffset());
    }
    /**
     * 秒时间戳转Str
     * @param secondTimeStamp 秒时间戳
     * @return LocalDateTime
     */
    public static String covertSecondTimeStampToStr(Long secondTimeStamp) {
        return covertSecondTimeStampToStr(secondTimeStamp,DateUtils.FULL_TIME_SPLIT_PATTERN);
    }
    /**
     * 秒时间戳转Str
     * @param secondTimeStamp 秒时间戳
     * @return str
     */
    public static String covertSecondTimeStampToStr(Long secondTimeStamp, String format) {
        LocalDateTime localDateTime = covertSecondTimeStampToLocalDateTime(secondTimeStamp);
        return coverLocalDateTimeToStr(localDateTime,format);
    }

    /**
     * Date转换为 LocalDateTime
     * @param date   date
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime convertDateToLocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }
    /**
     * LocalDateTime转换为 Date
     * @param time   time
     * @return {@link Date}
     */
    public static Date convertLocalDateTimeToDate(LocalDateTime time) {
        return Date.from(time.atZone(ZoneId.systemDefault()).toInstant());
    }
    /**
     * Date转str
     * @param date {@link Date} Date
     * @return  String 2020-10-20 10:10:10
     */
    public static String coverDateToStr(Date date) {
        return  coverDateToStr(date, DateUtils.FULL_TIME_SPLIT_PATTERN);
    }
    public static String coverDateToStr(Date date, String format) {
        LocalDateTime localDateTime = convertDateToLocalDateTime(date);
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format);
        return localDateTime.format(dateTimeFormatter);
    }
    /**
     * localDateTime转str
     * @param localDateTime {@link LocalDateTime} localDateTime
     * @return  String
     */
    public static String coverLocalDateTimeToStr(LocalDateTime localDateTime) {
        return coverLocalDateTimeToStr(localDateTime, DateUtils.FULL_TIME_SPLIT_PATTERN);
    }
    public static String coverLocalDateTimeToStr(LocalDateTime localDateTime, String format) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(format);
        return localDateTime.format(dateTimeFormatter);
    }

    /**
     * str转localDateTime
     * @param localDateTimeStr "2019-12-05 15:30:11"
     * @return  LocalDateTime 2019-12-05 15:30:11
     */
    public static LocalDateTime coverStrToLocalDateTime(String localDateTimeStr) {
        return LocalDateTime.parse(localDateTimeStr, DateTimeFormatter.ofPattern(DateUtils.FULL_TIME_SPLIT_PATTERN));
    }
    public static LocalDateTime coverStrToLocalDateTime(String localDateTimeStr, String format) {
        return LocalDateTime.parse(localDateTimeStr, DateTimeFormatter.ofPattern(format));
    }
    /**
     * 将字符串去掉 -
     * @param dateStr 2020-09-04
     * @return Integer   20200904
     */
    public static Integer convertStr2Int(String dateStr) {
        if (dateStr.equals("")) {
            return 0;
        }
        String concat = dateStr.replace("-", "");
        return Integer.parseInt(concat);
    }
    /**
     * 字符串转 LocalDateTime ，字符串格式 yyyy-MM-dd
     * @param localDateTime /
     * @return /
     */
    public static LocalDateTime parseLocalDateTimeFormat(String localDateTime, String pattern) {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.from(dateTimeFormatter.parse(localDateTime));
    }


    /**
     * 根据传入的格式，格式化时间
     *
     * @param date   Date
     * @param format 格式
     * @return 格式化后的字符串
     */
    public static String getDateFormat(Date date, String format) {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(format, Locale.CHINA);
        return simpleDateFormat.format(date);
    }
    /**
     * 格式化 CST类型的时间字符串
     * @param date   CST类型的时间字符串
     * @param format 格式
     * @return 格式化后的字符串
     * @throws ParseException 异常
     */
    public static String formatCstTime(String date, String format) throws ParseException {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(CST_TIME_PATTERN, Locale.US);
        Date usDate = simpleDateFormat.parse(date);
        return getDateFormat(usDate, format);
    }
    /**
     * 格式化 Instant
     * @param instant Instant
     * @param format  格式
     * @return 格式化后的字符串
     */
    public static String formatInstant(Instant instant, String format) {
        LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
        return localDateTime.format(DateTimeFormatter.ofPattern(format));
    }

    /**
     * 判断当前时间是否在指定时间范围
     * @param from 开始时间
     * @param to   结束时间
     * @return 结果
     */
    public static boolean between(LocalTime from, LocalTime to) {
        LocalTime now = LocalTime.now();
        return now.isAfter(from) && now.isBefore(to);
    }

    /**
     * 获取当前日期是周几
     * 1,2,3,4,5,6,7
     * @param date
     * @return int
     */
    public static Integer convertWeek(LocalDateTime date) {
        Date localDate = DateUtils.convertLocalDateTimeToDate(date);
        return  convertWeek(localDate);
    }
    public static Integer convertWeek(Date date) {
        int week = DateUtil.dayOfWeek(date);
        return  convertWeek(week);
    }
    public static Integer convertWeek(String date) {
        return convertWeek(date, DateUtils.FULL_TIME_SPLIT_PATTERN);
    }
    public static Integer convertWeek(String date, String format) {
        LocalDateTime localDateTime = DateUtils.parseLocalDateTimeFormat(date, format);
        Date localDate = DateUtils.convertLocalDateTimeToDate(localDateTime);
        int week = DateUtil.dayOfWeek(localDate);
        return  convertWeek(week);
    }
    public static Integer convertWeek(Integer day) {
        return  day == 1 ? 7 : day -1;
    }


    public static void main(String[] args) {
        System.out.println("当前时间戳- [毫秒] : "+getMilliByTime(LocalDateTime.now()));
        System.out.println("当前时间戳- [秒] : "+getSecondsByTime(LocalDateTime.now()));
        System.out.println("时间戳转LocalDateTime : "+covertSecondTimeStampToLocalDateTime(getSecondsByTime(LocalDateTime.now())));
        System.out.println("秒时间戳转Str : "+covertSecondTimeStampToStr(getSecondsByTime(LocalDateTime.now())));
        System.out.println("Date转换为 LocalDateTime : "+convertDateToLocalDateTime(new Date()));
        System.out.println("LocalDateTime转换为 Date : "+convertLocalDateTimeToDate(LocalDateTime.now()));
        System.out.println("Date转str : "+coverDateToStr(new Date(),DateUtils.FULL_TIME_SPLIT_PATTERN));
        System.out.println("localDateTime转str : "+coverLocalDateTimeToStr(LocalDateTime.now(),DateUtils.FULL_TIME_SPLIT_PATTERN));
        System.out.println("周几 : "+convertWeek(LocalDateTime.now()));
    }



    public static final String DATE_FORMAT_DAY = "yyyy-MM-dd";
    public static final String DATE_FORMAT_DAY_2 = "yyyy/MM/dd";
    public static final String TIME_FORMAT_SEC = "HH:mm:ss";
    public static final String DATE_FORMAT_SEC = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT_MSEC = "yyyy-MM-dd HH:mm:ss.SSS";
    public static final String DATE_FORMAT_MSEC_T = "yyyy-MM-dd'T'HH:mm:ss.SSS";
    public static final String DATE_FORMAT_MSEC_T_Z = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
    public static final String DATE_FORMAT_DAY_SIMPLE = "y/M/d";

    /**
     * 匹配yyyy-MM-dd
     */
    private static final String DATE_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$";
    /**
     * 匹配yyyy/MM/dd
     */
    private static final String DATE_REG_2 = "^[1-9]\\d{3}/(0[1-9]|1[0-2])/(0[1-9]|[1-2][0-9]|3[0-1])$";
    /**
     * 匹配y/M/d
     */
    private static final String DATE_REG_SIMPLE_2 = "^[1-9]\\d{3}/([1-9]|1[0-2])/([1-9]|[1-2][0-9]|3[0-1])$";
    /**
     * 匹配HH:mm:ss
     */
    private static final String TIME_SEC_REG = "^(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d$";
    /**
     * 匹配yyyy-MM-dd HH:mm:ss
     */
    private static final String DATE_TIME_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\\s" +
            "(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d$";
    /**
     * 匹配yyyy-MM-dd HH:mm:ss.SSS
     */
    private static final String DATE_TIME_MSEC_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])\\s" +
            "(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}$";
    /**
     * 匹配yyyy-MM-dd'T'HH:mm:ss.SSS
     */
    private static final String DATE_TIME_MSEC_T_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T" +
            "(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}$";
    /**
     * 匹配yyyy-MM-dd'T'HH:mm:ss.SSS'Z'
     */
    private static final String DATE_TIME_MSEC_T_Z_REG = "^[1-9]\\d{3}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])T" +
            "(20|21|22|23|[0-1]\\d):[0-5]\\d:[0-5]\\d\\.\\d{3}Z$";


    /**
     * <p>字符串时间转为{@link Date}类型，
     * 未找到匹配类型则抛出{@link FailedException}异常</p>
     * <p>支持匹配类型列表：</p>
     * <p>yyyy-MM-dd</p>
     * <p>yyyy/MM/dd</p>
     * <p>HH:mm:ss</p>
     * <p>yyyy-MM-dd HH:mm:ss</p>
     * <p>yyyy-MM-dd'T'HH:mm:ss.SSS</p>
     * <p>yyyy-MM-dd'T'HH:mm:ss.SSS'Z'</p>
     * <p>
     *
     * @param strDate 时间字符串
     * @return Date  {@link Date}时间
     * @throws ParseException 异常
     */
    public static Date str2Date(String strDate) throws ParseException {

        strDate = strDate.trim();
        SimpleDateFormat sdf = null;
        if (RegularUtils.isMatched(strDate, DATE_REG)) {
            sdf = new SimpleDateFormat(DATE_FORMAT_DAY);
        }
        if (RegularUtils.isMatched(strDate, DATE_REG_2)) {
            sdf = new SimpleDateFormat(DATE_FORMAT_DAY_2);
        }
        if (RegularUtils.isMatched(strDate, DATE_REG_SIMPLE_2)) {
            sdf = new SimpleDateFormat(DATE_FORMAT_DAY_SIMPLE);
        }
        if (RegularUtils.isMatched(strDate, TIME_SEC_REG)) {
            sdf = new SimpleDateFormat(TIME_FORMAT_SEC);
        }
        if (RegularUtils.isMatched(strDate, DATE_TIME_REG)) {
            sdf = new SimpleDateFormat(DATE_FORMAT_SEC);
        }
        if (RegularUtils.isMatched(strDate, DATE_TIME_MSEC_REG)) {
            sdf = new SimpleDateFormat(DATE_FORMAT_MSEC);
        }
        if (RegularUtils.isMatched(strDate, DATE_TIME_MSEC_T_REG)) {
            sdf = new SimpleDateFormat(DATE_FORMAT_MSEC_T);
        }
        if (RegularUtils.isMatched(strDate, DATE_TIME_MSEC_T_Z_REG)) {
            sdf = new SimpleDateFormat(DATE_FORMAT_MSEC_T_Z);
        }
        if (null != sdf) {
            return sdf.parse(strDate);
        }
        throw new FailedException(
                String.format("[%s] can not matching right time format", strDate));
    }

}
